package com.shoulder.core.http;

import lombok.Data;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;

@Data
public class HttpRequest {

    private final RestTemplate restTemplate;

    public HttpRequest(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    // GET 请求
    public <T> GetRequestBuilder<T> get(String url, Class<T> responseType) {
        return new GetRequestBuilder<>(url, responseType);
    }

    // POST 请求
    public <T> PostRequestBuilder<T> post(String url, Class<T> responseType) {
        return new PostRequestBuilder<>(url, responseType);
    }

    // PUT 请求
    public <T> PutRequestBuilder<T> put(String url, Class<T> responseType) {
        return new PutRequestBuilder<>(url, responseType);
    }

    // DELETE 请求
    public <T> DeleteRequestBuilder<T> delete(String url, Class<T> responseType) {
        return new DeleteRequestBuilder<>(url, responseType);
    }

    private abstract static class BaseRequestBuilder<T, B extends BaseRequestBuilder<T, B>> {
        protected final String url;
        protected final Class<T> responseType;
        protected final HttpHeaders headers = new HttpHeaders();
        protected MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();

        public BaseRequestBuilder(String url, Class<T> responseType) {
            this.url = url;
            this.responseType = responseType;
        }

        /**
         * 设置 Basic Auth
         */
        public B basicAuth(String username, String password) {
            String auth = username + ":" + password;
            String encodedAuth = Base64.getEncoder()
                    .encodeToString(auth.getBytes(StandardCharsets.UTF_8));
            headers.set("Authorization", "Basic " + encodedAuth);
            return self();
        }

        /**
         * 添加请求头
         */
        public B header(String headerName, String headerValue) {
            headers.add(headerName, headerValue);
            return self();
        }

        /**
         * 添加查询参数
         */
        public B queryParam(String name, String value) {
            queryParams.add(name, value);
            return self();
        }

        /**
         * 添加多个查询参数
         */
        public B queryParams(Map<String, String> params) {
            if (params != null) {
                params.forEach(queryParams::add);
            }
            return self();
        }

        /**
         * 执行请求并返回响应体
         */
        public T execute() {
            ResponseEntity<T> response = executeForEntity();
            return response.getBody();
        }

        /**
         * 执行请求并返回完整响应
         */
        public ResponseEntity<T> executeForEntity() {
            return doExecute();
        }

        protected abstract ResponseEntity<T> doExecute();

        @SuppressWarnings("unchecked")
        protected B self() {
            return (B) this;
        }

        protected String buildUrl() {
            return UriComponentsBuilder.fromHttpUrl(url)
                    .queryParams(queryParams)
                    .toUriString();
        }
    }

    /**
     * GET 请求构建器
     */
    public class GetRequestBuilder<T> extends BaseRequestBuilder<T, GetRequestBuilder<T>> {

        public GetRequestBuilder(String url, Class<T> responseType) {
            super(url, responseType);
        }

        @Override
        protected ResponseEntity<T> doExecute() {
            HttpEntity<Void> requestEntity = new HttpEntity<>(headers);
            return restTemplate.exchange(
                    buildUrl(),
                    HttpMethod.GET,
                    requestEntity,
                    responseType
            );
        }
    }

    /**
     * POST 请求构建器
     */
    public class PostRequestBuilder<T> extends BaseRequestBuilder<T, PostRequestBuilder<T>> {
        private Object requestBody;
        private MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<>();
        private String jsonBody;

        public PostRequestBuilder(String url, Class<T> responseType) {
            super(url, responseType);
        }

        /**
         * 设置表单参数
         */
        public PostRequestBuilder<T> formParam(String name, Object value) {
            formParams.add(name, value);
            return this;
        }

        /**
         * 设置多个表单参数
         */
        public PostRequestBuilder<T> formParams(Map<String, Object> params) {
            if (params != null) {
                params.forEach(formParams::add);
            }
            return this;
        }

        /**
         * 设置JSON请求体（字符串）
         */
        public PostRequestBuilder<T> jsonBody(String jsonBody) {
            this.jsonBody = jsonBody;
            return this;
        }

        /**
         * 设置请求体对象（会自动序列化为JSON）
         */
        public PostRequestBuilder<T> body(Object requestBody) {
            this.requestBody = requestBody;
            return this;
        }

        @Override
        protected ResponseEntity<T> doExecute() {
            HttpEntity<?> requestEntity = createRequestEntity();
            return restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    requestEntity,
                    responseType
            );
        }

        private HttpEntity<?> createRequestEntity() {
            if (requestBody != null) {
                headers.setContentType(MediaType.APPLICATION_JSON);
                return new HttpEntity<>(requestBody, headers);
            }
            if (jsonBody != null) {
                headers.setContentType(MediaType.APPLICATION_JSON);
                return new HttpEntity<>(jsonBody, headers);
            }
            if (!formParams.isEmpty()) {
                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                return new HttpEntity<>(formParams, headers);
            }
            return new HttpEntity<>(headers);
        }
    }

    /**
     * PUT 请求构建器
     */
    public class PutRequestBuilder<T> extends BaseRequestBuilder<T, PutRequestBuilder<T>> {
        private Object requestBody;
        private String jsonBody;

        public PutRequestBuilder(String url, Class<T> responseType) {
            super(url, responseType);
        }

        /**
         * 设置JSON请求体（字符串）
         */
        public PutRequestBuilder<T> jsonBody(String jsonBody) {
            this.jsonBody = jsonBody;
            return this;
        }

        /**
         * 设置请求体对象（会自动序列化为JSON）
         */
        public PutRequestBuilder<T> body(Object requestBody) {
            this.requestBody = requestBody;
            return this;
        }

        @Override
        protected ResponseEntity<T> doExecute() {
            HttpEntity<?> requestEntity = createRequestEntity();
            return restTemplate.exchange(
                    url,
                    HttpMethod.PUT,
                    requestEntity,
                    responseType
            );
        }

        private HttpEntity<?> createRequestEntity() {
            if (requestBody != null) {
                headers.setContentType(MediaType.APPLICATION_JSON);
                return new HttpEntity<>(requestBody, headers);
            }
            if (jsonBody != null) {
                headers.setContentType(MediaType.APPLICATION_JSON);
                return new HttpEntity<>(jsonBody, headers);
            }
            return new HttpEntity<>(headers);
        }
    }

    /**
     * DELETE 请求构建器
     */
    public class DeleteRequestBuilder<T> extends BaseRequestBuilder<T, DeleteRequestBuilder<T>> {

        public DeleteRequestBuilder(String url, Class<T> responseType) {
            super(url, responseType);
        }

        @Override
        protected ResponseEntity<T> doExecute() {
            HttpEntity<Void> requestEntity = new HttpEntity<>(headers);
            return restTemplate.exchange(
                    buildUrl(),
                    HttpMethod.DELETE,
                    requestEntity,
                    responseType
            );
        }
    }
}